﻿#define  _CRT_SECURE_NO_WARNINGS
#include<iostream>
//iostream为标准输入输出流，这里面兼容C语言的原因是，里面包含了C语言常用头文件stdio.h的功能，因此可以直接使用printf,scanf等函数
//函数局部域，全局域，命名空间域，类域
//上面四个作用域，是编译器进行存放变量，函数，类的地方
//如果没有特地指明，计算机会默认访问函数局部域与全局域里面的内容
//我们这里使用命名空间域是为了一些命名冲突（如果在全局域或者在函数局部域中已经存在的名字可以在命名空间域中设置）

//namespace hjc//命名空间域（使用一个关键词namespace再接一个命名空间的名字（可以自己任意创建）再加一对{}注意这里一个分号都没有）
//{
//	int a = 10;
//	int b = 20;
//	int Add(int x, int y)
//	{
//		return x + y;
//	}
//}
//
//int a = 1;
//int b = 2;
//double Add(double x, double y)
//{
//	return x + y;
//}
//
//
//int main()
//{
//	printf("%d \n", a);//这里使用的是全局域中的变量a
//	printf("%d \n", hjc::a);//这里使用的是命名空间域中的变量a
//	//C++中的::符号是范围运算符，用于解决名称冲突和访问其他范围中的标识符。不但可以访问命名空间域，函数局部域，类域等都可以进行访问
//
//
//	int c = 1;
//	int d = 2;
//	double e = 1.0;
//	double f = 2.0;
//	printf("%lf \n", Add(c, d));
//	printf("%lf \n", hjc::Add(c, d));//这里的Add函数的参数是int的类型，传递的参数也是int类型，那么其最后结果应该是一个int类型
//	//但是printf格式化输出的是浮点数类型的（在c++中可以进行隐式转换即从高精度转化为低精度的数据类型）
//
//
//	return 0;
//}

// 命名空间域可以嵌套使用
//namespace Person
//{
//	namespace xh
//	{
//		int age = 20;
//		int Add(int x, int y)
//		{
//			return x + y;
//		}
//	}
//	namespace xm
//	{
//		int age = 18;
//		double Add(double x, double y)
//		{
//			return x + y;
//		}
//	}
//	
//
//}
//
//int main()
//{
//	printf("%d \n", Person::xh::age);
//	printf("%d \n", Person::xm::age);
//	printf("%d \n", Person::xh::Add(1, 6));
//	printf("%lf \n", Person::xm::Add(1.0, 6.2));
//
//	return 0;
//}

//这里是将整个命名空间进行展开，我们平时在自己练习时，可以这样做，但是如果我们写一些大型项目时，不建议直接将其全部展开，可以使用下面的指定展开
//using namespace std;
//
//namespace std
//{
//	int a=10;
//	int b = 20;
//
//}
//
////这里是指定命名空间展开，只将命名空间中的某个变量进行展开使用
//using std::cout;
//using std::endl;
//
////std是编译器中的一个标准库（standrad),我们使用的cin,cout,endl等函数都是在这里面来的
//int main()
//{
//	cout << std::a << endl;
//	return 0;
//}

//using namespace std;
////1.全缺省参数
//void fun1(int a = 10, int b = 20, int c = 30)
//{
//	cout << "a=" << a << endl;
//	cout << "b=" << b << endl;
//	cout << "c=" << c << endl;
//}
//
////2.半缺省参数
////void fun2(int a, int b = 20, int c )//半缺省参数必须是从右往左进行传参数，不能跳过一个传参要按照顺序，否则会进行报错
//void fun2(int a, int b = 20, int c = 30)
//{
//	cout << "a=" << a << endl;
//	cout << "b=" << b << endl;
//	cout << "c=" << c << endl;
//}
//
//int main()
//{
////这叫做缺省参数，我们在定义函数时就给函数的参数赋一个值，然后系统就会将其认为是个默认值，然后在我们调用函数时，如果我们没有给函数传参数，那么就使用默认参数
//	fun1();
//	cout << endl;
//	fun1(1);
//	cout << endl;
//	fun1(1,2);
//	cout << endl;
//	fun1(1,2,300);
//	cout << endl;
//	fun2(1);//这里由于我们没有给第一个参数初始化，那么我们在调用该函数时就必须要对该函数的第一个参数进行传参，其他的参数都
//	cout << endl;
//	fun2(11,2);
//
//	return 0;
//}

//函数重载：就是一个函数名，可以实现多个功能，函数重载的要求如下：
//1.函数的参数类型不同；
//2.函数的参数个数不同；
//3.函数的参数类似顺序不同（注意：一定是参数的数据类型不同才能构成重载，因为参数的变量是个变化的值，改变它的顺序，实质上并没有改变参数的顺序）

//using namespace std;
//
//void fun( )
//{
//	cout << "这是" << "fun( )" << "类型的" << endl;
//}
//
//void fun(int a, int b)
//{
//	cout << "这是" << "fun(int,int )" << "类型的" << endl;
//}
//
//void fun(char a, char b)
//{
//	cout << "这是" << "fun(char,char )" << "类型的" << endl;
//}
//
//void fun(int a, char b)
//{
//	cout << "这是" << "fun(int,char )" << "类型的" << endl;
//}
//
//
//void fun(char a, int b)
//{
//	cout << "这是" << "fun(char,int )" << "类型的" << endl;
//}
//
//void fun(int a)
//{
//	cout << "这是" << "fun(int)" << "类型的" << endl;
//}
//
////注意：这里如果函数返回值不同不会构成函数重载，构成函数重载的条件只有上面三条，
////int fun(int a)
////{
////	cout << "这是" << "fun(int)" << "类型的" << endl;
////}
//
//int main()
//{
//	fun(1, 2);
//	fun('a','b');
//	fun(1, 'a');
//	fun('a', 1);
//	fun(1);
//	fun('a');
//
//	return 0;
////}
//
//using namespace std;
//
////这里我们使用了c++中的引用和函数重载，我们之前在写一个交换函数的时候都是传递参数的指针（地址）来进行交换的，现在我们直接使用引用就可以实现了
////引用是对原来的变量取一个别名，那样我们在对形参（使用引用）进行相应操作时，实参也进行了相应的操作了。因为引用只是对对象取一个别名，那么他们是共用一个内存空间的
//void Swap(int& x, int& y)
//{
//	int tmp = x;
//	x = y;
//	y = tmp;
//}
//
//void Swap(float& x, float& y)
//{
//	float tmp = x;
//	x = y;
//	y = tmp;
//}
//
//
//
//int main()
//{
	//int a = 1;
	//int b = 2;
	//cout << "交换前:a=" << a <<"  " << "b=" << b << endl;
	//Swap(a, b);
	//cout << "交换前:a=" << a << "  " << "b=" << b << endl;
	//float c = 1.2;
	//float d = 2.3;
	//cout << "交换前:c=" << c << "  " << "d=" << d << endl;
	//Swap(c, d);
	//cout << "交换前:c=" << c << "  " << "d=" << d << endl;
	
	//下面的例子就是引用，我们可以对一个对象取好几个别名，还可以对别名取别名
	//int a = 10;
	//int& b = a;
	//int& c = a;
	//int& d = b;
	//int e = 20;
	//d = e;//这里是赋值操作，我们将e的值赋值给d那么a,b,c,d同时改变值，因为他们共用一个内存空间的
	//cout << a << endl;
	//cout << b << endl;
	//cout << c << endl;
	//cout << d << endl;

//	return 0;
//}
//引用有以下三个特性：
//1.使用引用的时候，我们必须要使用初始化
//2.我们使用引用只能针对一个对象，但是一个对象可以有多个别名
//3.我们引用一但确定了哪个对象后就不能随便改变指向了

//
//#include<iostream>
//#include<assert.h>
//using namespace std;
//typedef int STDataType;
//typedef struct Stack
//{
//	STDataType* a;
//	int top;//这个top值指向的是有效数据的下一位空闲位置
//	int capacity;
//}ST;
//void STInit(ST& rs, int n = 4)//缺省参数，初始化了，刚开始定义了栈的空间大小为4
//{
//	rs.a = (STDataType*)malloc(n * sizeof(STDataType));
//	rs.top = 0;
//	rs.capacity = n;
//}
//// 栈顶 
//void STPush(ST& rs, STDataType x)
//{
//	// 满了， 扩容 
//	if (rs.top == rs.capacity)
//	{
//		printf("扩容\n");
//		int newcapacity = rs.capacity == 0 ? 4 : rs.capacity * 2;
//		STDataType* tmp = (STDataType*)realloc(rs.a, newcapacity *
//			sizeof(STDataType));
//		if (tmp == NULL)
//		{
//			perror("realloc fail");
//			return;
//		}
//		rs.a = tmp;
//		rs.capacity = newcapacity;
//	}
//	rs.a[rs.top] = x;
//	rs.top++;
//}
//// int STTop(ST& rs)
//int& STTop(ST& rs)//函数的返回值使用了引用，等会我们直接使用函数名调用即可
//{
//	assert(rs.top > 0);
//	return rs.a[rs.top-1];
//}
//int main()
//{
//	// 调⽤全局的 
//	ST st1;
//	STInit(st1);//由于在初始化时，我们没有给栈的空间大小传递参数，于是它就使用我们给的缺省参数
//	//STPush（）这个函数，由于其在定义函数时参数使用了引用方法，于是形参的改变就直接改变了实参st1的值了
//	STPush(st1, 1);
//	STPush(st1, 2);
//	cout << STTop(st1) << endl;
//	STTop(st1) += 10;
//	cout << STTop(st1) << endl;
//	return 0;
//}
 
 
 
// 
//#include<iostream>
//using namespace std;
//typedef struct SeqList
//{
//	int a[10];
//	int size;
//}SLT;
//
//void SeqPushBack(SLT& sl, int x)
//{}
//typedef struct ListNode
//{
//	int val;
//	struct ListNode* next;
//}LTNode, * PNode;//我们重命名类型，后有两个名字：一个是结点类型名字，一个是指针类型名字
//// 指针变量也可以取别名，这⾥LTNode*& phead就是给指针变量取别名 ，前面的LTNode*就是phead的数据类型，于是我们对其进行引用操作
//// 这样就不需要⽤⼆级指针了，相对⽽⾔简化了程序 
////void ListPushBack(LTNode** phead, int x)
////void ListPushBack(LTNode*& phead, int x)
//void ListPushBack(PNode& phead, int x)
//{
//	PNode newnode = (PNode)malloc(sizeof(LTNode));
//	newnode->val = x;
//	newnode->next = NULL;
//	if (phead == NULL)
//	{
//		phead = newnode;
//	}
//	else
//	{
//		//...
//	}
//}
//
//int main()
//{
//	PNode plist = NULL;
//	ListPushBack(plist, 1);
//	return 0;
//}
//



//using namespace std;
//int main()
//{
//	int a = 10;
//	const int& ra = a;
//	cout << a << endl;
//	cout << ra << endl;
//	const int b = 20;
//	//int& rb = b;//这里我们无法使用引用操作，因为我们的原变量是const int 类型的，对于有const修饰的数据类型，其权限就会被缩小，它只能够读而不能够被修改
//	const int& rb = b;
//	cout << b << endl;
//	cout << rb << endl;
//
//	const int& ra1 = a * 3;//对于=右边的是一个表达式时，无法直接进行引用，
//	//我们要使用const引用才可以，因为我们在使用一个表达式进行赋值时，它首先计算结果传递给临时中间值才可以，这个临时中间值是一个常量值（只能读不能改）相当于锁了一个const
//	//如果我们直接使用int&的话，就会间接地放大权限了，这就不符合const的引用规则了
//	cout << ra1 << endl;
//	double d = 12.34;//这里也是的，计算机里面可以进行隐式类型转换，但是它也要有一个临时中间变量才可以，故后面与上面差不多
//	const int& rd = d;
//
//
//	return 0;
//}


//using namespace std;
//int main()
//{
//	char a = 'a';
//	char& ra = a;//使用引用
//	char* pa = &a;//使用指针
//	//现在我们来计算一下，引用和指针分别占据多少字节大小
//	cout << sizeof(a) << endl;//1
//	cout << sizeof(pa)<< endl;//4
//	//上面的结果我们知道了：引用还是原来那个内存空间于是我们计算其字节大小时就是计算这个字符类型变量的字节数，但是对于指针来说，我们是使用指针指向目标对象的内存空间
//	//于是我们在计算指针时，其实是算的是地址，对于地址而言它与环境有关系：在X32环境下为4个字节大小，在X64环境下为8个字节大小。
//	return 0;
//}
//using namespace std;
//#define Add(a,b) ((a)+(b))
////inline关键字是内联函数的关键字，inline修饰函数时就是内联函数，那么在调用函数时就会展开内联函数而不进行函数栈帧的创建与销毁了。
////但是inline修饰的函数一般是一些比较短小的函数（十行左右），虽然减少了进行函数栈帧的创建与销毁的开销，但是每次调用该内联函数时都进行展开，一旦函数体过于巨大，就会导致代码膨胀
////故我们使用inline修饰的函数一般都是一些比较短小而出现频繁的函数（我们这里的inline内联函数对标着C语言中的宏）
////内联函数是否展开，可以打开反汇编查看是否有call指令，如果有就说明没有展开，如果没有就说明展开了。
//inline int  fun()
//{
//	int red = 1;
//	red++;
//	red++;
//	red++;
//	red++;
//	red++;
//	return red;
//
//}
//
//int main()
//{
//	fun();
//	cout << Add(1, 2) << endl;
//	cout << ((1) + (2)) << endl;//这是宏Add展开内联产生的，直接将参数代入进去，并替换函数体
//	return 0;
//}

//using namespace std;
////使用函数重载来判断，NULL在c++中对应着什么。
//void fun(int* x)
//{
//	cout << "fun(int*x)" << endl;
//}
//
//void fun(int  x)
//{
//	cout << "fun(int x)" << endl;
//}
//
//int main()
//{
//	fun(0);
//	fun(NULL);//由运行结果，我们可以看出来了在c++中，NULL表示的是字面值0，并不是空指针。这里我们要记住
//	fun(nullptr);//在c++中，我们把nullptr作为空指针
//	//fun((void*)0);//注意：这样写是错误的，void作为泛型，不可以作为指针类型进行强转。
//	return 0;
//}